APO OneAgent 设计思路
之前的文章介绍过APO是如何使用Grafana Alloy采集prometheus生态的指标体系。这篇文章介绍APO是如何采集Trace和log的,这两项数据的采集存在以下问题:
- 日志需要配置采集的日志目录,并不是每个应用的日志目录都非常规范,这就导致配置工作量的增加
- Trace需要配置针对语言的Agent完成数据采集
- 在容器环境不管是修改镜像或者使用init Container方式,都有挺多配置的工作
OneAgent的设计目标
OneAgent的设计目标是尽量减少用户的配置工作,尽快的完成数据的采集。在设计过程中,参考了很多的业界先进的技术实现,比如datadog的onestep agent的实现机制,另外重要的就是Odigos这家公司的实现。Datadog不用做更多的介绍,这里简单介绍下Odigos这家公司:Odigos的口号是“Instant Distributed Tracing”,有兴趣可以访问其官网:https://odigos.io/ ,OpenTelmetry 的 GO auto instrument 项目:https://github.com/open-telemetry/opentelemetry-go-instrumentation 就是由该公司捐献的。
Odigos开源的https://github.com/odigos-io/odigos 实现中能够实现以下功能:
- 基于应用当前已经启动的POD进行语言识别
- 基于K8s manifest挂载对应语言的探针文件和配置到对应的应用
- 通过更新K8s manifest触发应用重启以应用探针
为了实现OneAgent的设计目标,我们调整了Odigos的执行流程,使用Webhook将'更新K8s manifest'和'应用重启'两个步骤进行了分离:
- 更新内容以patch形式存储到应用的Annotations中
- 用户手动重启pod时,通过webhook拦截pod创建请求,应用Annotations中保存的patch
这样可以避免用户对整个Namespace装载探针时,集群所有应用同时重启,造成资源紧张;而是预先设置好探针配置,在应用下次更新时,自动完成探针的添加。
Odigos中没有包含非K8s应用的实现,我们采用了Linux的Preload机制来完成下面的工作:
- 通过LD_PRELOAD加载Preload库,在应用启动前拦截启动命令,完成语言识别和后续工作
- 基于识别到的语言设置探针配置,通常以特定的环境变量加入到启动命令
- 将改造后的启动命令交给Linux继续执行,完成应用的启动和探针的应用
为了实现OneAgent的设计目标,我们调整了Odigos的执行流程,使用Webhook将'更新K8s manifest'和'应用重启'两个步骤进行了分离:
- 更新内容以patch形式存储到应用的Annotations中
- 用户手动重启pod时,通过webhook拦截pod创建请求,应用Annotations中保存的patch
这样可以避免用户对整个Namespace装载探针时,集群所有应用同时重启,造成资源紧张;而是预先设置好探针配置,在应用下次更新时,自动完成探针的添加。
Odigos中没有包含非K8s应用的实现,我们采用了Linux的Preload机制来完成下面的工作:
- 通过LD_PRELOAD加载Preload库,在应用启动前拦截启动命令,完成语言识别和后续工作
- 基于识别到的语言设置探针配置,通常以特定的环境变量加入到启动命令
- 将改造后的启动命令交给Linux继续执行,完成应用的启动和探针的应用
针对日志数据的采集,我们采用了阿里开源的 https://github.com/alibaba/ilogtail 工具,它有下面一些优点:
- 基于Linux的inotify机制,相较于轮询读取文件,消耗更低
- 内置一套设计良好的插件系统,性能开销较大的采集阶段使用C语言实现,确保高效;后续处理采用Go实现,可以快速的进行数据完善和处理
- 内置的采集插件支持了对父级目录下日志文件检索,避免用户手动配置每个应用日志地址
在ilogtail基础上,我们实现了功能增强插件,用于统计需要的日志指标,填充日志进程信息和日志数据采样。
程序语言的自动识别
目前的程序语言识别均基于启动命令特征和启动文件信息:
- JAVA: 检查启动命令是否满足 java [-options] class [args。。。] 或 java [-options] -jar jarfile [args。。。] 格式
- PYTHON: 检查启动命令中是否包含python
- Golang: 读取启动文件的内容,检查是否有可识别的buildInfo信息
- NodeJS: 检查启动命令中和启动文件路径中是否包含node
- Dotnet: 检查启动环境变量中的环境变量名中是否包含DOTNET和ASPNET